package com.eu.ebpm.engine.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.eu.ebpm.engine.entity.args.BusinessParam;
import com.eu.ebpm.engine.entity.args.StartupParam;
import com.eu.ebpm.engine.entity.deploy.Deploy;
import com.eu.ebpm.engine.entity.deploy.Mission;
import com.eu.ebpm.engine.entity.runtime.Execution;
import com.eu.ebpm.engine.entity.runtime.ExecutionVariable;
import com.eu.ebpm.engine.entity.runtime.TaskEntity;
import com.eu.ebpm.engine.exception.ErrorCode;
import com.eu.ebpm.engine.exception.NonactivatedExcpetion;
import com.eu.ebpm.engine.exception.WorkFlowException;
import com.eu.ebpm.engine.express.VariableType;
import com.eu.ebpm.engine.init.EbpmCache;
import com.eu.ebpm.engine.pvm.EngineServiceType;
import com.eu.ebpm.engine.pvm.PvmContainer;
import com.eu.ebpm.engine.repository.DeployRepository;
import com.eu.ebpm.engine.repository.ExecutionRepository;
import com.eu.ebpm.engine.repository.ExecutionVariableRepository;
import com.eu.ebpm.engine.service.ExecutionService;
import com.eu.ebpm.engine.util.JdkObjectSerializableUtils;

@Service
public class ExecutionServiceImpl implements ExecutionService {
	
	@Autowired
	private PvmContainer pvmContainer;
	
	@Autowired
	private ExecutionRepository executionRepository;
	
	@Autowired
	private ExecutionVariableRepository executionVariableRepository;
	
	@Autowired
	private DeployRepository deployRepository;
	
	public Execution startProcessInstanceByKey(String key) {
		return startProcessInstanceByKey(key, null, null);
	}
	
	public Execution startProcessInstanceByKey(String key, StartupParam arg) {
		return startProcessInstanceByKey(key, null, arg);
	}
	
	public Execution startProcessInstanceByKey(String key, BusinessParam businessArg) {
		return startProcessInstanceByKey(key, businessArg, null);
	}
	
	@Transactional
	public Execution startProcessInstanceByKey(String key, BusinessParam businessArg, StartupParam permitArg) {
		
		Deploy deploy = EbpmCache.getDeployByKey(key);

		// 1、判断流程是否激活
		boolean isActive = deployRepository.isActive(deploy.getId());
		if (!isActive) {
			throw new NonactivatedExcpetion(ErrorCode.RU_NONACTIVATED);
		}
		
		// 2、判断是否具有启动流程的权限
		Mission startMission = deploy.getStartMission();
		if (!startMission.isPermitToStart(permitArg)) {
			throw new WorkFlowException(ErrorCode.RU_NO_PERMISSION_START);
		}
		
		String businessKey = null;
		String businessDesc = null;
		String businessType = null;
		Map<String, Object> vs = null;
		if(businessArg != null) {
			businessKey = businessArg.getAndRemoveBusinessKey();
			businessDesc = businessArg.getAndRemoveBusinessDesc();
			businessType = businessArg.getAndRemoveBusinessType();
			vs = businessArg.getMap();
		}
		
		String assignee = null;
		if(permitArg != null && permitArg.getAssignee() != null) {
			assignee = permitArg.getAssignee().toString();
		}
		
		//3、插入运行时流程
		Execution e = new Execution(assignee, deploy.getName(), deploy.getDesc(), businessKey, businessDesc, businessType, 0L, deploy.getId(), new Date());
		executionRepository.insert(e);
		
		//4、插入运行时参数
		if(vs != null) {
			for(String name : vs.keySet()) {
				executionVariableRepository.insert(new ExecutionVariable(name, vs.get(name), VariableType.typeOf(vs.get(name)), e.getId()));
			}
		}
		
		TaskEntity task = new TaskEntity();
		task.setExecutionId(e.getId());
		task.setExecution(e);
		task.setRootExecutionId(e.getId());
		if(assignee != null) {
			task.setAssignee(assignee);
			task.setAssigneeTime(new Date());
		}
		
		//5、执行流程调度服务
		pvmContainer.getPvmService(EngineServiceType.START_EVENT).execute(startMission, task, vs);
		
		e.setTask(task);
		return e;
	}
	
	public <T> T getVariable(long executionId, String variableName) {
		
		List<ExecutionVariable> vs = executionVariableRepository.list(executionId, variableName);
		
		if(vs.size() == 0) return null;
		
		ExecutionVariable ev = vs.get(0);
		
		return JdkObjectSerializableUtils.toObject(ev.getData());
	}

	
	public Map<String, Object> getVariables(long executionId) {
		
		List<ExecutionVariable> vs = executionVariableRepository.list(executionId, null);
		
		Map<String, Object> map = new HashMap<String, Object>();
		
		for(ExecutionVariable e : vs) {
			map.put(e.getName(), e.getType().transform(e.getValue()));
		}
		
		return map;
	}
	
	
	public void removeVariable(long executionId, String variableName) {
		executionVariableRepository.remove(executionId, variableName);
	}
	
	public void removeProcessByExeId(int executionId) {
//		List<Integer> taskIds = query.queryIds("select id_ as id from wf_ru_task where executionId_ = ?", executionId);
//		for(int tId : taskIds) {
//			remove("delete from wf_ru_taskidentity where taskId_ = ?", tId);
//		}
//		remove("delete from wf_ru_task where executionId_ = ?", executionId);
//		remove("delete from wf_ru_variable where executionId_ = ?", executionId);
//		remove("delete from wf_ru_execution where id_ = ?", executionId);
	}

	public void setVariable(long executionId, String name, Object value) {
		executionVariableRepository.insert(new ExecutionVariable(name, value, VariableType.typeOf(value), executionId));
	}
	
}































